/* @(#)GlyphDictionary.java
** 
** Copyright (C) 2012 by Steven D. Stamps
**
**             Trademarks & Copyrights
** Flywheel Management Science(TM), Flywheel Management Model(TM),
** Flywheel Story Editor(TM) and FlywheelMS(TM) are exclusive trademarks
** of Steven D. Stamps and may only be used freely for the purpose of
** identifying the unforked version of this software.  Subsequent forks
** may not use these trademarks.  All other rights are reserved.
** and FlywheelMS(TM) are exclusive trademarks of Steven D. Stamps
** and may only be used freely for the purpose of identifying the
** unforked version of this software.  Subsequent forks (if any) may
** not use these trademarks.  All other rights are reserved.
**
** DecKanGL (Decorated Kanban Glyph Language) and TribKn (Tribal Knowledge)
** are also exclusive trademarks of Steven D. Stamps.  These may be used
** freely within the unforked FlywheelMS application and documentation.
** All other rights are reserved.
**
** gConGUI (game Controller Graphical User Interface) is an exclusive
** trademark of Steven D. Stamps.  This trademark may be used freely
** within the unforked FlywheelMS application and documentation.
** All other rights are reserved.
**
** Trademark information is available at
** <http://www.flywheelms.com/trademarks>
**
** Flywheel Management Science(TM) is a copyrighted body of management
** metaphors, governance processes, and leadership techniques that is
** owned by Steven D. Stamps.  These copyrighted materials may be freely
** used, without alteration, by the community (users and developers)
** surrounding this GPL3-licensed software.  Additional copyright
** information is available at <http://www.flywheelms.org/copyrights>
**
**              GPL3 Software License
** This program is free software: you can use it, redistribute it and/or
** modify it under the terms of the GNU General Public License, version 3,
** as published by the Free Software Foundation. This program is distributed
** in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
** even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
** PURPOSE.  See the GNU General Public License for more details. You should
** have received a copy of the GNU General Public License, in a file named
** COPYING, along with this program.  If you cannot find your copy, see
** <http://www.gnu.org/licenses/gpl-3.0.html>.
*/

package com.flywheelms.library.deckangl.glyph;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;

import com.flywheelms.library.R;
import com.flywheelms.library.deckangl.enumerator.DecoratorCanvasLocation;
import com.flywheelms.library.deckangl.enumerator.WorkStateColor;
import com.flywheelms.library.deckangl.interfaces.DecKanGlDecorator;
import com.flywheelms.library.deckangl.interfaces.DecKanGlNoun;
import com.flywheelms.library.fmm.node.impl.enumerator.CompletableWorkState;

/**
 * @author sstamps
 */
public abstract class DecKanGlDictionary {

//	private static final int width_ANNOTATION_LEFT_MARGIN = 4;
//	private static final int width_ANNOTATION_RIGHT_MARGIN = 10;
//	private static final int height_CANVAS_MARGINS = 6;
//	private static final float width_ANNOTATION_CHARACTER = 5.43f;
//	private static final int height_ANNOTATION_TOP_MARGIN = 12;
//	private static final int height_ANNOTATION_ROW = 14;
//	private static final int height_TOP_GLYPH_MARGIN = 2;
//	private static final int width_GLYPH_RIGHT_MARGIN = 8;

	protected static final boolean IS_PROTOTYPE_ICON = true;

	// DecKanGl defaults.  Override associated getters (if needed) in the implementation of DecKanGlDictionary.
	private static int margin_NOUN_STATUS_LEFT = 2;
	private static int margin_NOUN_STATUS_RIGHT = 2;
	private static int margin_NOUN_STATUS_TOP = 2;
	private static int margin_NOUN_STATUS_BOTTOM = 2;

	private static int margin_CANVAS_LEFT = 1;
	private static int margin_CANVAS_RIGHT = 1;
	private static int margin_CANVAS_TOP = 1;
	private static int margin_CANVAS_BOTTOM = 1;
	
	private static int width_LEFT_ZONE = 6;
	private static int width_RIGHT_ZONE = 6;
	
	private static int height_LEFT_CORNER_DECORATORS = 7;
	private static int height_RIGHT_CORNER_DECORATORS = 7;

	private static int overlap_BOTTOM_ZONE_DECORATORS = 1;
	private static int overlap_LEFT_ZONE_DECORATORS = 1;
	private static int overlap_RIGHT_ZONE_DECORATORS = 1;
	private static int overlap_TOP_ZONE_DECORATORS = 1;

	private static int height_LEFT_MIDDLE_DECORATORS = 7;
	private static int height_RIGHT_MIDDLE_DECORATORS = 7;
	
	private static int height_TOP_ZONE = 5;
	private static int height_BOTTOM_ZONE = 5;
	
	private static int width_TOP_END_DECORATORS = 8;
	private static int width_TOP_MIDDLE_DECORATOR = 9;
	private static int width_BOTTOM_END_DECORATORS = 8;
	private static int width_BOTTOM_MIDDLE_DECORATOR = 9;
	

	protected static LinkedHashMap<String, NounDefinition> completableNounMap;
	protected static LinkedHashMap<String, WorkStatus> workStatusMap;
	private static LinkedHashMap<String, NounWorkStatus> nounWorkStatusMap;
	protected static LinkedHashMap<String, TribKnQualityMetric> tribKnQualityMetricMap;
	
	protected GlyphCache decKanGlGlyphCache = new GlyphCache();
	
	protected static DecKanGlDictionary instance;
	
	protected DecKanGlDictionary() {
		DecKanGlDictionary.instance = this;
		completableNounMap = buildNounDefinitionMap();
		workStatusMap = buildWorkStatusMap();
		tribKnQualityMetricMap = buildTribKnQualityMetricMap();
		disableUnusedDecoratorZones();
	}

	public static DecKanGlDictionary getInstance() {
		return DecKanGlDictionary.instance;
	}

	public Collection<NounDefinition> getCompletableNounCollection() {
		return getCompletableNounMap().values();
	}

	public HashMap<String, NounDefinition> getCompletableNounMap() {
		return completableNounMap;
	}

	public Collection<WorkStatus> getStatusCollection() {
		return getStatusMap().values();
	}

	public HashMap<String, WorkStatus> getStatusMap() {
		return workStatusMap;
	}

	public Collection<TribKnQualityMetric> getTribKnCollection() {
		return getTribKnMap().values();
	}

	private static HashMap<String, TribKnQualityMetric> getTribKnMap() {
		return tribKnQualityMetricMap;
	}

	public TribKnQualityMetric getTribKn(String aTribKnName) {
		return getTribKnMap().get(aTribKnName);
	}
	
	public void disableUnusedDecoratorZones() {
		if (	!tribKnUsesCanvasLocation(DecoratorCanvasLocation.left_zone_TOP) &&
				!tribKnUsesCanvasLocation(DecoratorCanvasLocation.left_zone_MIDDLE) &&
				!tribKnUsesCanvasLocation(DecoratorCanvasLocation.left_zone_BOTTOM) ) {
			width_LEFT_ZONE = 0;
			CanvasZone.LEFT_ZONE.setWidth(0);
		}
		if (	!tribKnUsesCanvasLocation(DecoratorCanvasLocation.right_zone_TOP) &&
				!tribKnUsesCanvasLocation(DecoratorCanvasLocation.right_zone_MIDDLE) &&
				!tribKnUsesCanvasLocation(DecoratorCanvasLocation.right_zone_BOTTOM) ) {
			width_RIGHT_ZONE = 0;
			CanvasZone.RIGHT_ZONE.setWidth(0);
		}
		if (	!tribKnUsesCanvasLocation(DecoratorCanvasLocation.top_zone_LEFT) &&
				!tribKnUsesCanvasLocation(DecoratorCanvasLocation.top_zone_MIDDLE) &&
				!tribKnUsesCanvasLocation(DecoratorCanvasLocation.top_zone_RIGHT) ) {
			height_TOP_ZONE = 0;
			CanvasZone.TOP_ZONE.setHeight(0);
		}
		if (	!tribKnUsesCanvasLocation(DecoratorCanvasLocation.bottom_zone_LEFT) &&
				!tribKnUsesCanvasLocation(DecoratorCanvasLocation.bottom_zone_MIDDLE) &&
				!tribKnUsesCanvasLocation(DecoratorCanvasLocation.bottom_zone_RIGHT) ) {
			height_BOTTOM_ZONE = 0;
			CanvasZone.BOTTOM_ZONE.setHeight(0);
		}
	}

	private static boolean tribKnUsesCanvasLocation(DecoratorCanvasLocation theCanvasLocation) {
		for (TribKnQualityMetric theDecKanGlTribKn : getInstance().getTribKnCollection()) {
			if (theDecKanGlTribKn.getLogicalCanvasLocation() == theCanvasLocation) {
				return true;
			}
		}
		return false;
	}

	// Must be over-ridden in the implementing Dictionary
	protected LinkedHashMap<String, TribKnQualityMetric> buildTribKnQualityMetricMap() {
		return null;
	}

	private LinkedHashMap<String, NounWorkStatus> buildNounWorkStatusMap() {
		LinkedHashMap<String, NounWorkStatus> theNounWorkStatusMap =
				new LinkedHashMap<String, NounWorkStatus>();
		for (NounDefinition theNoun : getCompletableNounCollection()) {
			for (WorkStateColor theDecKanGlStatusColor : WorkStateColor.values()) {
				theNounWorkStatusMap.put(
						buildNounWorkStatusMapKey(theNoun, theDecKanGlStatusColor),
						new NounWorkStatus(
								theNoun,
								theDecKanGlStatusColor ) );
			}
		}
		return theNounWorkStatusMap;
	}

	public DecKanGlGlyph getDecKanGlGlyph(DecKanGlNoun aDecKanGlNoun) {
		String theSyntheticGlyphKey = GlyphCache.synthesizeGlyphKey(aDecKanGlNoun);
		DecKanGlGlyph theDecKanGlGlyph = GlyphCache.get(theSyntheticGlyphKey);
		if (theDecKanGlGlyph == null) {
			theDecKanGlGlyph = buildDecKanGlGlyph(aDecKanGlNoun);
			GlyphCache.put(
					theSyntheticGlyphKey,
					theDecKanGlGlyph );
		} else {
//			FmsGuiHelper.makeToast("Using Glyph Cache with key = " + theSyntheticGlyphKey);
		}
		return theDecKanGlGlyph;
	}

	private DecKanGlGlyph buildDecKanGlGlyph(DecKanGlNoun aDecKanGlNoun) {
		return new DecKanGlGlyph(
				getNounWorkStatus(aDecKanGlNoun),
				new GlyphCanvas(
						getNounWorkStatus(aDecKanGlNoun).getBitmapResourceId(),
						aDecKanGlNoun.getDecKanGlDecoratorMap(),
						getInstance() ) );
	}
	
	public NounWorkStatus getNounWorkStatus(DecKanGlNoun aDecKanGlNoun) {
		return getNounWorkStatusMap().get(buildNounWorkStatusMapKey(aDecKanGlNoun));
	}
	
	public NounWorkStatus getNounWorkStatus(String aClassName, CompletableWorkState aCompletableWorkState) {
		String theWorkStatusMapKey = aClassName + "-" + aCompletableWorkState.getWorkStateColorName();
		return getNounWorkStatusMap().get(theWorkStatusMapKey);
	}
	
	// key to retrieve a map entry
	private static String buildNounWorkStatusMapKey(DecKanGlNoun aDecKanGlNoun) {
		return
				aDecKanGlNoun.getNounDefinition().getName() +
				"-" +
				aDecKanGlNoun.getDecKanGlWorkStateColor().getName();
	}
	
	// creating a key for a new map entry
	private static String buildNounWorkStatusMapKey(NounDefinition aNounDefinition, WorkStateColor aWorkStatusColor) {
		return
				aNounDefinition.getName() +
				"-" +
				aWorkStatusColor.getName();
	}

	public static void putDecorator(
			HashMap<DecoratorCanvasLocation, DecKanGlDecorator> aDecoratorMap,
			DecKanGlDecorator aDecKanGlDecorator) {
		if (aDecKanGlDecorator != null) {
			aDecoratorMap.put(
					aDecKanGlDecorator.getTribKnQualityMetric().getLogicalCanvasLocation(),
					aDecKanGlDecorator);
		}
	}
	
//	protected static Drawable buildDecKanGlDrawableZoom(
//			DecKanGlGlyph aDecKanGlGlyph) {
//		// TODO
//		return null;
//	}
	
	public LinkedHashMap<String, NounWorkStatus> getNounWorkStatusMap() {
		if (nounWorkStatusMap == null) {
			nounWorkStatusMap = buildNounWorkStatusMap();
		}
		return nounWorkStatusMap;
	}

	// Must be over-ridden in the implementing Dictionary
	protected abstract LinkedHashMap<String, NounDefinition> buildNounDefinitionMap();

	public NounDefinition getCompletableNoun(String aNounName) {
		return getCompletableNounMap().get(aNounName);
	}

	// Must be over-ridden in the implementing Dictionary
	protected abstract LinkedHashMap<String, WorkStatus> buildWorkStatusMap();

	public WorkStatus getStatus(String aStatusName) {
		return getStatusMap().get(aStatusName);
	}
	

	public int getDecoratorBackgroundColor() {
		return R.color.canvas__decorator_background;
	}

	public int getDecoratorBackgroundColorMediumAlpha() {
		return R.color.canvas__decorator_background__medium_alpha;
	}

	public int getDecoratorBackgroundColorLightAlpha() {
		return R.color.canvas__decorator_background__light_alpha;
	}

	public int getNounBackgroundColor() {
		return R.color.canvas__noun_background;
	}

	public int getWidthLeftZone() {
		return DecKanGlDictionary.width_LEFT_ZONE;
	}

	public int getWidthRightZone() {
		return DecKanGlDictionary.width_RIGHT_ZONE;
	}

	public int getHeightLeftCornerDecorators() {
		return DecKanGlDictionary.height_LEFT_CORNER_DECORATORS;
	}

	public int getHeightRightCornerDecorators() {
		return DecKanGlDictionary.height_RIGHT_CORNER_DECORATORS;
	}

	public int getHeightLeftMiddleDecorators() {
		return DecKanGlDictionary.height_LEFT_MIDDLE_DECORATORS;
	}

	public int getHeightRightMiddleDecorators() {
		return DecKanGlDictionary.height_RIGHT_MIDDLE_DECORATORS;
	}

	public int getHeightTopZone() {
		return DecKanGlDictionary.height_TOP_ZONE;
	}

	public int getHeightBottomZone() {
		return DecKanGlDictionary.height_BOTTOM_ZONE;
	}

	public int getWidthTopEndDecorators() {
		return DecKanGlDictionary.width_TOP_END_DECORATORS;
	}

	public int getWidthTopMiddleDecorator() {
		return DecKanGlDictionary.width_TOP_MIDDLE_DECORATOR;
	}

	public int getWidthBottomEndDecorators() {
		return DecKanGlDictionary.width_BOTTOM_END_DECORATORS;
	}

	public int getWidthBottomMiddleDecorator() {
		return DecKanGlDictionary.width_BOTTOM_MIDDLE_DECORATOR;
	}
	
	public int getMarginCanvasLeft() {
		return DecKanGlDictionary.margin_CANVAS_LEFT;
	}
	
	public int getMarginCanvasRight() {
		return DecKanGlDictionary.margin_CANVAS_RIGHT;
	}
	
	public int getMarginCanvasTop() {
		return DecKanGlDictionary.margin_CANVAS_TOP;
	}
	
	public int getMarginCanvasBottom() {
		return DecKanGlDictionary.margin_CANVAS_BOTTOM;
	}
	
	public int getMarginNounStatusLeft() {
		return DecKanGlDictionary.margin_NOUN_STATUS_LEFT;
	}
	
	public int getMarginNounStatusRight() {
		return DecKanGlDictionary.margin_NOUN_STATUS_RIGHT;
	}
	
	public int getMarginNounStatusTop() {
		return DecKanGlDictionary.margin_NOUN_STATUS_TOP;
	}
	
	public int getMarginNounStatusBottom() {
		return DecKanGlDictionary.margin_NOUN_STATUS_BOTTOM;
	}

	public int getOverlapBottomZoneDecorators() {
		return DecKanGlDictionary.overlap_BOTTOM_ZONE_DECORATORS;
	}

	public int getOverlapLeftZoneDecorators() {
		return DecKanGlDictionary.overlap_LEFT_ZONE_DECORATORS;
	}

	public int getOverlapRightZoneDecorators() {
		return DecKanGlDictionary.overlap_RIGHT_ZONE_DECORATORS;
	}

	public int getOverlapTopZoneDecorators() {
		return DecKanGlDictionary.overlap_TOP_ZONE_DECORATORS;
	}

	public int getHeightLeftZone() {
		return (getHeightLeftCornerDecorators() * 2) +
				getHeightLeftMiddleDecorators() -
				(getOverlapLeftZoneDecorators() * 2);
	}

	public int getHeightRightZone() {
		return (getHeightRightCornerDecorators() * 2) +
				getHeightRightMiddleDecorators() -
				(getOverlapRightZoneDecorators() * 2);
	}

	public int getWidthTopZone() {
		return (getWidthTopEndDecorators() * 2) +
				getWidthTopMiddleDecorator() -
				(getOverlapTopZoneDecorators() * 2);
	}

	public int getWidthBottomZone() {
		return (getWidthBottomEndDecorators() * 2) +
				getWidthBottomMiddleDecorator() -
				(getOverlapBottomZoneDecorators() * 2);
	}
	
	public static boolean decoratorsUseZone(
			HashMap<DecoratorCanvasLocation, DecKanGlDecorator> aDecoratorMap,
			CanvasZone aCanvasZone) {
		for (DecKanGlDecorator theDecKanGlDecorator : aDecoratorMap.values()) {
			if (theDecKanGlDecorator.isEnabled() &&
				theDecKanGlDecorator.getTribKnQualityMetric().getLogicalCanvasLocation().getGlyphCanvasZone() ==
					aCanvasZone) {
				return true;
			}
		}
		return false;
	}
	
	public abstract NounDefinition getNounDefinitionForName(String aName);
	
	public abstract String getDecoratorsPackageName();

}